package com.atguigu.gamll.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.result.RetVal;
import com.atguigu.gmall.result.RetValCodeEnum;
import com.atguigu.gmall.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
public class AuthGlobalFilter implements GlobalFilter {

    @Autowired
    private RedisTemplate redisTemplate;

    //filterWhiteList=trade.html,myOrder.html,list.html
    @Value("${filter.whiteList}")
    private String filterWhiteList;
    // 创建匹配对象
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    // 拦截过滤方法
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("TEST");
        ServerHttpRequest request = exchange.getRequest();   //获取请求request
        ServerHttpResponse response = exchange.getResponse();// 获取响应
        //获取请求当中的路径 如这里只会得到search.html路径 http://search.gmall.com/search.html?keyword=三星
        String path = request.getURI().getPath(); //用户登录之后自动跳转的路径地址
        //这个path中不能访问/sku/getSkuInfo/{skuId}中的数据信息，拦截内部的请求
        if (antPathMatcher.match("/sku/**", path)) {
            return writeDataToBrowser(response, RetValCodeEnum.NO_PERMISSION);
        }
        String userId = this.getLoginUserId(request);
        //redis中，登录信息过期了 让重新登录
        if (userId == null)
            return writeDataToBrowser(response, RetValCodeEnum.FAIL);

        if ("-1".equals(userId))     //cookie被盗 提示没有权限
            return writeDataToBrowser(response, RetValCodeEnum.NO_PERMISSION);

        if (!this.checkUserLoginOrNot(userId, path))
            return writeDataToBrowser(response, RetValCodeEnum.NO_LOGIN); //需要登录才能继续操作

        //如果要看订单相关信息是需要进行登录的
       /* if (antPathMatcher.match("/order/**", path)) {
            //如果是未登录情况,提示未登录
            if (StringUtils.isEmpty(userId))
                return writeDataToBrowser(response, RetValCodeEnum.NO_LOGIN);
        }*/

        //访问拦截路径名单 对于这些请求路径需要进行拦截
        for (String filterWhite : filterWhiteList.split(",")) {
            //用户访问的url中包含上述数据，并且用户未登录,让用户去登录
            if (path.indexOf(filterWhite) != -1 && StringUtils.isEmpty(userId)) {
                //设置完成之后重定向
                response.setStatusCode(HttpStatus.SEE_OTHER);
                response.getHeaders().set(HttpHeaders.LOCATION, "http://www.gmall.com/login.html?originalUrl=" + request.getURI());
                return response.setComplete();
            }
        }
        //如果说用户登录了呢，那么我们就需要将userId放到request中
        if (!StringUtils.isEmpty(userId)) {
            //将用户id放入header当中
            request.mutate().header("userId", userId).build();
            return chain.filter(exchange.mutate().request(request).build());
        }
        // TODO: 2021/9/5 关闭临时id添加数据到购物车
        //获取用户的临时id信息,用户添加购物车信息，
     /*   String userTempId = this.getUserTempId(request);
        if (!StringUtils.isEmpty(userTempId)){
            //说明用户没有登录，那么userid一定是空的
            request.mutate().header("userTempId",userTempId).build();
            return chain.filter(exchange.mutate().request(request).build());
        }*/
        return chain.filter(exchange);
    }

    /*
     * 获取登录用户id信息(反着写代码)
     * 1.用户id信息存储在redis中
     * 2.那么就得先拼接redis的key---> String userKey = RedisConst.USER_LOGIN_KEY_PREFIX+token;
     * 3.如何拿到token 从cookie(pc端) header(移动端)
     */
    private String getLoginUserId(ServerHttpRequest request) {

        String token = "";
        //header一般存储在移动端
        List<String> result = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(result)) {
            token = result.get(0);
        } else {
            //如果header中没有获取到token 那么从cookie里面去获取
            HttpCookie cookie = request.getCookies().getFirst("token");
            if (cookie != null) {
                token = cookie.getValue();
            }
        }
        if (!StringUtils.isEmpty(token)) {
            //根据token获取用户登录信息
            String userKey = "user:login:" + token;
            String loginInfoJson = (String) redisTemplate.opsForValue().get(userKey);
            //如果登录信息过期了怎么办，
            if (StringUtils.isEmpty(loginInfoJson))
                return null;//重新赋值一份到redis
            JSONObject loginInfo = JSONObject.parseObject(loginInfoJson);
            String loginIp = loginInfo.getString("loginIp");
            String currentIpAddress = IpUtil.getGatwayIpAddress(request); //获取到登录时ip
            //判断当前电脑登录ip是否与存储ip一致 如果一致取得userId,如果不一致返回"-1"
            if (loginIp.equals(currentIpAddress)) {
                //防止cookie被盗用所以做了一步判断
                return loginInfo.getString("userId");
            } else {
                return "-1";
            }
        }
        return null;
    }

    /*如果用户未登录，获取用户的临时id*/
    private String getUserTempId(ServerHttpRequest request) {
        // 获取header中的数据
        String userTempId = "";
        List<String> result = request.getHeaders().get("userTempId");
        // 判断集合不为空！
        if (!CollectionUtils.isEmpty(result)) {
            userTempId = result.get(0);
        } else {
            // 表示在header 中没有获取到数据，从cookie中获取
            HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
            if (httpCookie != null) {
                userTempId = httpCookie.getValue();
            }
        }
        return userTempId;
    }

    private Mono<Void> writeDataToBrowser(ServerHttpResponse response, RetValCodeEnum retValCodeEnum) {
        RetVal<Object> retVal = RetVal.build(null, retValCodeEnum);
        //把对象转换为字节
        byte[] bytes = JSONObject.toJSONString(retVal).getBytes(StandardCharsets.UTF_8);
        //将字节数组变为一个数据buffer
        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);
        //设置页面的头部信息为返回json数据编码为utf-8
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(dataBuffer));
    }

    /*检查用户登录情况，如果要想访问，请先登录*/
    public boolean checkUserLoginOrNot(String userId,String path) {
        if (StringUtils.isEmpty(userId)) { //空的检查，不是空不会检查
            if (antPathMatcher.match("/order/**", path)) //订单
                return false;
            if (antPathMatcher.match("/cart/**", path)) //购物车
                return false;
            if (antPathMatcher.match("/seckill/**", path)) //秒杀
                return false;
            // TODO: 2021/9/5
        }
        return true;
    }
}